﻿using System;
using System.IO;
using System.Text;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using Object = UnityEngine.Object;
namespace GameEditor
{
    /// <summary>
    /// AB文件创建器
    /// </summary>
	public static class AssetBundleBuilder
    {
        /// <summary>
        /// 清空AB文件的标记
        /// </summary>
        public static void ClearMarks()
        {
            string[] names = AssetDatabase.GetAllAssetBundleNames();
            if (names.Length < 1)
                return;
            int startIndex = 0;
            EditorApplication.update = delegate ()
            {
                for (int i = 0; i < names.Length; i++)
                {
                    string name = names[startIndex];
                    EditorUtility.DisplayProgressBar("清理标记中", name, (float)(startIndex+1) / (float)names.Length);
                    AssetDatabase.RemoveAssetBundleName(name, true);
                    startIndex++;
                    if (startIndex >= names.Length)
                    {
                        EditorUtility.ClearProgressBar();
                        EditorApplication.update = null;
                        startIndex = 0;
                        Debug.Log("清理完毕");
                        break;
                    }
                }
            };
        }

        /// <summary>
        /// 开始打包
        /// </summary>
        /// <param name="buildTarget"></param>
        public static void BuildAssetBundles(string exportPath,BuildTarget buildTarget, BuildAssetBundleOptions options)
        {
            if (Directory.Exists(exportPath))
            {
                Directory.Delete(exportPath, true);
            }
            Directory.CreateDirectory(exportPath);
            DateTime oldTime = DateTime.Now;
            BuildPipeline.BuildAssetBundles(exportPath, options, buildTarget);
            TimeSpan span = DateTime.Now.Subtract(oldTime);
            Debug.Log("打包完毕，本次打包耗时:" + span.TotalSeconds + "秒!");
        }

        /// <summary>
        /// 清理多余的Manifest
        /// </summary>
        public static void ClearManifest(string path) {
            string[] files = Directory.GetFiles(path, "*.manifest", SearchOption.AllDirectories);
            string dirName = Path.GetFileName(path);
            foreach (var each in files.Where(s => (Path.GetFileNameWithoutExtension(s)) != dirName)) {
                File.Delete(each);
            }
        }



        /// <summary>
        /// 打包指定资源
        /// </summary>
        /// <param name="obj"></param>
        /// <param name="bundleName">包名</param>
        /// <param name="outPath">输出路径</param>
        /// <param name="buildTarget">输出目标</param>
        public static void BuildAssetBundle(Object obj, string bundleName, string outPath, BuildAssetBundleOptions options, BuildTarget buildTarget)
        {
            AssetBundleBuild build = new AssetBundleBuild();
            build.assetBundleName = bundleName;
            build.assetBundleVariant = EditorConst.ABSuffix;
            build.assetNames = new string[] { AssetDatabase.GetAssetPath(obj) };
            BuildPipeline.BuildAssetBundles(outPath, new AssetBundleBuild[] { build }, options, buildTarget);
        }


        /// <summary>
        /// 打包选中资源
        /// 1.支持多选
        /// 2.支持文件夹
        /// 3.支持指定资源
        /// </summary>
        /// <param name="buildTarget"></param>
        public static void BuildSelectAssetBundles(BuildAssetBundleOptions options, BuildTarget buildTarget)
        {

            if (Selection.objects != null)
            {
                Dictionary<string, AssetBundleBuild> abBuilds = new Dictionary<string, AssetBundleBuild>();
                for (int i = 0; i < Selection.objects.Length; i++)
                {
                    Object obj = Selection.objects[i];
                    string path = AssetDatabase.GetAssetPath(obj);
                    string fullPath = EditorUtil.GetFullPath(path);
                    //如果是一个目录
                    if (Directory.Exists(fullPath))
                    {
                        BuildSelectFloder(path, abBuilds);
                    }
                    //如果是一个资源
                    else
                    {
                        BuildSelectAsset(path, abBuilds);
                    }
                }
                BuildSelectAssetBundles(abBuilds, options, buildTarget);
            }
        }

        /// <summary>
        /// 打包选中资源
        /// </summary>
        /// <param name="abNames"></param>
        /// <param name="buildTarget"></param>
        public static void BuildSelectAssetBundles(Dictionary<string, AssetBundleBuild> buildMap, BuildAssetBundleOptions options, BuildTarget buildTarget)
        {
            string exportPath = Application.streamingAssetsPath + "/Select";
            if (Directory.Exists(exportPath))
                Directory.Delete(exportPath, true);
            Directory.CreateDirectory(exportPath);
            DateTime oldTime = DateTime.Now;
            AssetBundleBuild[] builds = new AssetBundleBuild[buildMap.Count];
            buildMap.Values.CopyTo(builds, 0);
            BuildPipeline.BuildAssetBundles(exportPath, builds, options, buildTarget);
            TimeSpan span = DateTime.Now.Subtract(oldTime);
            Debug.Log("打包完毕，本次打包耗时:" + span.TotalSeconds + "秒!");
        }

        /// <summary>
        /// 是否标记过了
        /// </summary>
        /// <param name="ai"></param>
        /// <returns></returns>
		public static bool IsMarked(AssetImporter ai)
        {
            return ai != null && !string.IsNullOrEmpty(ai.assetBundleName) && !string.IsNullOrEmpty(ai.assetBundleVariant);
        }

        /// <summary>
        /// 打包选中的文件夹
        /// </summary>
        /// <param name="path"></param>
        /// <param name="abNames"></param>
        public static void BuildSelectFloder(string path, Dictionary<string, AssetBundleBuild> buildMap)
        {
            AssetImporter ai = AssetImporter.GetAtPath(path);
            //如果文件夹被标记了
            if (IsMarked(ai) && !buildMap.ContainsKey(ai.assetBundleName))
            {
                AssetBundleBuild build = new AssetBundleBuild();
                build.assetBundleName = ai.assetBundleName;
                build.assetBundleVariant = ai.assetBundleVariant;
                build.assetNames = AssetDatabase.GetAssetPathsFromAssetBundle(ai.assetBundleName + "." + ai.assetBundleVariant);
                buildMap.Add(build.assetBundleName, build);
                string[] dependencies = AssetDatabase.GetDependencies(build.assetNames, true);
                for (int i = 0; i < dependencies.Length; i++)
                {
                    BuildSelectAsset(dependencies[i], buildMap);
                }
            }
            else
            {
                string fullPath = EditorUtil.GetFullPath(path);
                string[] files = Directory.GetFiles(fullPath);
                for (int i = 0; i < files.Length; i++)
                {
                    BuildSelectAsset(EditorUtil.GetAssetsPath(files[i]), buildMap);
                }
                string[] directorys = Directory.GetDirectories(fullPath);
                for (int i = 0; i < directorys.Length; i++)
                {
                    BuildSelectFloder(EditorUtil.GetAssetsPath(directorys[i]), buildMap);
                }
            }
        }

        /// <summary>
        /// 打包选中的资源
        /// </summary>
        /// <param name="assetPath">资源路径</param>
        /// <param name="abNames"></param>
        public static void BuildSelectAsset(string assetPath, Dictionary<string, AssetBundleBuild> buildMap)
        {
            AssetImporter ai = AssetImporter.GetAtPath(assetPath);
            if (IsMarked(ai) && !buildMap.ContainsKey(ai.assetBundleName))
            {
                AssetBundleBuild build = new AssetBundleBuild();
                build.assetBundleName = ai.assetBundleName;
                build.assetBundleVariant = ai.assetBundleVariant;
                build.assetNames = AssetDatabase.GetAssetPathsFromAssetBundle(ai.assetBundleName + "." + ai.assetBundleVariant);
                buildMap.Add(build.assetBundleName, build);
                string[] dependencies = AssetDatabase.GetDependencies(build.assetNames, true);
                for (int i = 0; i < dependencies.Length; i++)
                {
                    BuildSelectAsset(dependencies[i], buildMap);
                }
            }
        }

        /// <summary>
        /// 标记一个文件夹一个资源包
        /// </summary>
        /// <param name="path">路径</param>
        /// <param name="prefix">AB包路径前缀</param>
        public static void MarkOneFloderOneBundle(string path)
        {
            string fullPath = EditorUtil.FixedWindowsPath(Application.dataPath + "/" + path);
            if (Directory.Exists(fullPath))
            {
                string assetPath = EditorUtil.GetAssetsPath(fullPath);
                AssetImporter ai = AssetImporter.GetAtPath(assetPath);
                ai.SetAssetBundleNameAndVariant(path, EditorConst.ABSuffix);
               // MarkOneAssetOneBundleWithFullPath(fullPath, true, path);
            }
            else
            {
                Debug.LogError("标记文件夹出错,不存在的文件路径:" + fullPath);
            }
        }


        /// <summary>
        /// 标记指定路径下的所有子文件夹
        /// </summary>
        /// <param name="path">指定路径</param>
        /// <param name="prefix">AB包路径前缀</param>
        public static void MarkSubFloderOneBundle(string path)
        {
            string fullPath = EditorUtil.FixedWindowsPath(Application.dataPath + "/" + path);
            if (Directory.Exists(fullPath))
            {
                string[] paths = Directory.GetDirectories(fullPath);
                for (int i = 0; i < paths.Length; i++)
                {
                    string tmpPath = EditorUtil.FixedWindowsPath(paths[i]).Replace(Application.dataPath + "/", string.Empty);
                    MarkOneFloderOneBundle(tmpPath);
                }
            }
            else
            {
                Debug.LogError("标记子文件夹出错,不存在的文件路径:" + fullPath);
            }
        }

        /// <summary>
        /// 标记文件夹下的所有指定类型资源
        /// </summary>
        /// <param name="path">路径</param>
        /// <param name="types">类型白名单</param>
        /// <param name="includeChildDirectory">是否包含子文件夹</param>
        /// <param name="prefix">AB包路径前缀</param>
        public static void MarkOneAssetOneBundle(string path, bool includeChildDirectory = false)
        {
            string fullPath = EditorUtil.FixedWindowsPath(Application.dataPath + "/" + path);
            if (Directory.Exists(fullPath))
            {
                MarkOneAssetOneBundleWithFullPath(fullPath, includeChildDirectory);
            }
            else
            {
                Debug.LogError("标记文件夹下的资源出错,不存在的文件路径:" + fullPath);
            }
        }

        /// <summary>
        /// 标记一个文件夹下的资源
        /// </summary>
        /// <param name="path"></param>
        /// <param name="includeChildDirectory">是否包含子文件夹</param>
        public static void MarkOneAssetOneBundleWithFullPath(string path, bool includeChildDirectory, string bundleName = "")
        {
            string[] files = Directory.GetFiles(path);
            foreach (var file in files.Where(file => !file.Contains(".meta")))
            {
                string fullPath = EditorUtil.FixedWindowsPath(file);
                string assetPath = EditorUtil.GetAssetsPath(fullPath);
                string extension = Path.GetExtension(fullPath);
                AssetImporter ai = AssetImporter.GetAtPath(assetPath);
                if (ai == null)
                    continue;
                string assetBundleName = !string.IsNullOrEmpty(bundleName) ? bundleName : assetPath.Replace("Assets/", string.Empty).Replace(extension, string.Empty);
                ai.SetAssetBundleNameAndVariant(assetBundleName, EditorConst.ABSuffix);
            }
            if (includeChildDirectory)
            {
                string[] infos = Directory.GetDirectories(path);
                for (int i = 0; i < infos.Length; i++)
                {
                    MarkOneAssetOneBundleWithFullPath(infos[i], includeChildDirectory, bundleName);
                }
            }
        }


 

    }



}
